package com.winsdom.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.winsdom.context.BaseContext;
import com.winsdom.domain.BuildingMessage;
import com.winsdom.domain.PropertyInfoMessage;
import com.winsdom.domain.dto.AddFeeDTO;
import com.winsdom.domain.dto.PropertyInfoDTO;
import com.winsdom.domain.vo.FormulaPriceVO;
import com.winsdom.domain.po.MessagePO;
import com.winsdom.domain.vo.PropertyInfoFeeVO;
import com.winsdom.dto.CategoryTreeNodes;
import com.winsdom.entity.*;
import com.winsdom.enums.RedisKey;
import com.winsdom.exception.BaseException;
import com.winsdom.mapper.*;
import com.winsdom.mapper.mapper.ProjectManagementMapper;
import com.winsdom.service.*;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.fasterxml.jackson.core.type.TypeReference;
import org.springframework.util.StringUtils;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 项目管理 服务实现类
 */
@Slf4j
@Service
public class ProjectManagementServiceImpl implements ProjectManagementService {

    // 获取日志记录器
    Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private ProjectManagementMapper projectManagementMapper;
    @Autowired
    private ICategoryService iCategoryService;
    @Autowired
    private BuildingMapper buildingMapper;
    @Autowired
    private PropertyInfoMapper propertyInfoMapper;
    @Autowired
    private IFeeFormulaService iFeeFormulaService;
    @Autowired
    private IBillingAssociationService iBillingAssociationService;
    @Autowired
    private IUserProjectsService iUserProjectsService;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;


    @Override
    public List<CategoryTreeNodes> getOrganizationTree() {
        //获取当前账号信息
        Long userId = Long.valueOf(BaseContext.getCurrentId());
        if (userId == null) {
            throw new BaseException("该账号异常");
        }
        log.info("用户id：{}",userId);
        Long categoryId = Long.valueOf(BaseContext.getCategoryId());
        if (categoryId == null) {
            throw new BaseException("该账号异常");
        }
        log.info("用户组织id：{}",categoryId);

        String cacheKey = RedisKey.ORGANIZATION.getValue()+userId;
        List<CategoryTreeNodes> categoryTreeNodesStream = null;
        try {
            //从 Redis 获取缓存数据
            categoryTreeNodesStream = (List<CategoryTreeNodes>) redisTemplate.opsForValue().get(cacheKey);
        } catch (Exception e) {
            log.error("从Redis获取组织树数据失败: {}", e.getMessage(), e);
        }

        if(categoryTreeNodesStream == null) {
            try {
                // 1. 获取根节点
                List<CategoryTreeNodes> categoryTreeNodes = categoryMapper.selectAll();
                categoryTreeNodesStream =
                        categoryTreeNodes.stream()
                                .filter(node -> node.getId().equals(categoryId))
                                .collect(Collectors.toList());
                if (categoryTreeNodesStream.isEmpty()) {
                    return Collections.emptyList();
                }

                // 2. 获取当前账号管理的楼盘分类ID集合
                LambdaQueryWrapper<UserProjects> projectQueryWrapper = new LambdaQueryWrapper<>();
                projectQueryWrapper.eq(UserProjects::getUserId, userId)
                        .select(UserProjects::getCategoryId);
                List<UserProjects> userProjects = iUserProjectsService.list(projectQueryWrapper);
                Set<Long> allowedCategoryIds = userProjects.stream()
                        .map(UserProjects::getCategoryId)
                        .collect(Collectors.toSet());
                for (CategoryTreeNodes node : categoryTreeNodesStream) {
                    if (node == null) {
                        continue;
                    }
                    // 3. 递归构建子树并过滤type=3的节点
                    buildSubTreeAndFilter(node, allowedCategoryIds);
                }
                //加入缓存
                if (categoryTreeNodesStream != null) {
                    //将查询结果存入Redis缓存
                    redisTemplate.opsForValue().set(cacheKey, categoryTreeNodesStream, 1, TimeUnit.HOURS);
                }
            }catch (Exception e) {
                log.error("查询组织资源失败: {}", e.getMessage(), e);
                return null;
            }

        }

        return categoryTreeNodesStream;
    }

    /**
     * 构建子树并过滤type=3的节点
     * @param parentNode 父节点
     * @param allowedCategoryIds 允许的categoryId集合
     */
    private void buildSubTreeAndFilter(CategoryTreeNodes parentNode, Set<Long> allowedCategoryIds) {
        // 查询子节点
        List<CategoryTreeNodes> children = categoryMapper.getChildrenByParentIdBy6(parentNode.getId());

        if (children.isEmpty()) {
            parentNode.setChildren(null);
            return;
        }

        // 过滤子节点集合
        List<CategoryTreeNodes> filteredChildren = new ArrayList<>();
        for (CategoryTreeNodes child : children) {
            // 递归处理子节点的子树
            buildSubTreeAndFilter(child, allowedCategoryIds);

            // 对于type=3的节点，检查是否在允许列表中
            if (child.getType() == 3 && !allowedCategoryIds.contains(child.getId())) {
                // 不满足条件，跳过该节点
                continue;
            }

            filteredChildren.add(child);
        }

        // 设置过滤后的子节点
        parentNode.setChildren(filteredChildren.isEmpty() ? null : filteredChildren);
    }


    @Override
    public BuildingMessage getBuildingMessage(Long id) {
        return getMessageWithParentName(
                id,
                projectManagementMapper::getBuildingMessage,
                BuildingMessage::getParentId,
                BuildingMessage::setParentname
        );
    }

    @Override
    public PropertyInfoMessage getPropertyInfoMessage(Long id) {
        PropertyInfoMessage propertyInfoMessage = getMessageWithParentName(
                id,
                projectManagementMapper::getPropertyInfoMessage,
                PropertyInfoMessage::getParentId,
                PropertyInfoMessage::setParentname
        );

        ObjectMapper objectMapper = new ObjectMapper();
        try {
            // 解析 areaCode 字段
            if (propertyInfoMessage.getAreaCode() != null && !propertyInfoMessage.getAreaCode().isEmpty()) {
                List<String> areaCodeList = objectMapper.readValue(propertyInfoMessage.getAreaCode(), new TypeReference<List<String>>() {});
                propertyInfoMessage.setAreaCodeList(areaCodeList); // 设置解析后的数组
                propertyInfoMessage.setAreaCode(null);
            }

            // 解析 propertyArea 字段
            if (propertyInfoMessage.getPropertyArea() != null && !propertyInfoMessage.getPropertyArea().isEmpty()) {
                List<String> propertyAreaList = objectMapper.readValue(propertyInfoMessage.getPropertyArea(), new TypeReference<List<String>>() {});
                propertyInfoMessage.setPropertyAreaList(propertyAreaList); // 设置解析后的数组
                propertyInfoMessage.setPropertyArea(null);
            }
        } catch (Exception e) {
            logger.error("解析 areaCode 或 propertyArea 时出错", e);
            throw new BaseException("解析 areaCode 或 propertyArea 时出错");
        }

        return propertyInfoMessage;
    }


    /**
     * 通用消息查询方法（带父级名称）
     * @param id 分类ID
     * @param messageFetcher 消息获取函数
     * @param parentIdGetter 父级ID获取方法
     * @param parentNameSetter 父级名称设置方法
     * @param <T> 消息类型
     * @return 包含父级名称的消息对象
     */
    private <T> T getMessageWithParentName(
            Long id,
            Function<Long, T> messageFetcher,
            Function<T, Long> parentIdGetter,
            BiConsumer<T, String> parentNameSetter
    ) {
        validateId(id); // 验证ID是否有效

        T message = messageFetcher.apply(id); // 根据ID获取消息对象
        if (message == null) {
            logger.error("查询结果为空，分类 ID: {}", id); // 如果查询结果为空，记录日志
            throw new BaseException("未找到与分类 ID: " + id + " 相关的信息"); // 抛出异常
        }

        Long parentId = parentIdGetter.apply(message); // 获取消息对象的父级ID
        if (parentId != null) {
            Category category = categoryMapper.selectById(parentId); // 根据父级ID查询父级分类信息
            if (category != null) {
                parentNameSetter.accept(message, category.getName()); // 如果父级分类存在，设置父级名称
            }
        }
        return message; // 返回最终的消息对象
    }

    // 公共的 ID 检查逻辑
    private void validateId(Long id) {
        if (id == null) {
            logger.error("分类 ID 不能为空");
            throw new BaseException("请选择需要查询的分类");
        }
    }


    @Override
    public MessagePO getMessage(Long id) {
        validateId(id); // 验证ID是否有效
        //查询信息
        Category category = categoryMapper.selectById(id);
        if(category==null){
            logger.error("没有查询到数据");
            throw new BaseException("没有查询到数据");
        }
        //查询父类信息
        LambdaQueryWrapper<Category> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Category::getId,category.getParentId());
        Category category1 = categoryMapper.selectOne(wrapper);
        //将查询的数据封装
        MessagePO messageVO = new MessagePO();
        BeanUtils.copyProperties(category,messageVO);
        messageVO.setParentname(category1.getName());
        return messageVO;
    }

    @Override
    public void updateMessage(MessagePO messagePO) {
        if (messagePO == null) {
            logger.error("传入的对象为空");
            throw new BaseException("修改内容不能为空");
        }
        if(messagePO.getId()!=null){
            if(messagePO.getName()!=null && messagePO.getName()!=""){
                if(messagePO.getStatus()!=null){
                    Category category = new Category();
                    BeanUtils.copyProperties(messagePO,category);
                    categoryMapper.updateById(category);
                    //修改状态
                    updateStatus(messagePO.getParentId(),messagePO.getStatus());
                }else {
                    throw new BaseException("请填写状态");
                }
            }else {
                throw new BaseException("请填写修改的名称");
            }
        }else {
            throw new BaseException("请选择需要查询的分类");
        }

    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateBuilding(Building building) {
        //验证数据
        validateBuilding(building);
            //修改信息
            int i = buildingMapper.updateBuilding(building);
            if(i<=0){
                logger.error("信息修改失败");
                throw new BaseException("信息修改失败");
            }
            //修改状态
            updateStatus(building.getId(),building.getStatus());
    }

    /**
     * 验证楼栋信息是否有效
     *
     * @param building 楼栋对象
     * @return 验证结果
     */
    private void validateBuilding(Building building) {
        if (building == null) {
            logger.error("传入的楼栋对象为空");
            throw new BaseException("传入的楼栋对象为空");
        }

        if (building.getBuildingName() == null || building.getBuildingName().trim().isEmpty()) {
            logger.error("楼栋名称为空");
            throw new BaseException("楼栋名称为空");
        }

        if (building.getProjectName() == null || building.getProjectName().trim().isEmpty()) {
            logger.error("项目名称为空");
            throw new BaseException("项目名称为空");
        }

        if (building.getNumber() == null || building.getNumber().trim().isEmpty()) {
            logger.error("项目编号为空");
            throw new BaseException("项目编号为空");
        }

        if (building.getStatus() == null) {
            logger.error("状态为空");
            throw new BaseException("状态为空");
        }
    }

    public void updateStatus(Long id,Integer status){
        //判断该层级下面有没有下级(停用)
        if(status==0){
            LambdaQueryWrapper<Category> objectLambdaQueryWrapper = new LambdaQueryWrapper<>();
            objectLambdaQueryWrapper.eq(Category::getParentId, id).eq(Category::getStatus, 1);
            List<Category> categories = iCategoryService.list(objectLambdaQueryWrapper);
            if (!categories.isEmpty()) {
                logger.error("该层级下面有下级不能停用");
                throw new BaseException("该层级下面有下级不能停用");
            }
            int a=categoryMapper.updateStatus(id,status);
            if(a<=0){
                logger.error("id"+id+"的状态修改失败");
                throw new BaseException("id"+id+"的状态修改失败");
            }
        }else if(status==1){
            int i = categoryMapper.updateStatus(id, status);
            if(i<=0){
                logger.error("id"+id+"的状态修改失败");
                throw new BaseException("id"+id+"的状态修改失败");
            }
        }else {
            throw new BaseException("修改失败");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updatePropertyInfo(PropertyInfoDTO propertyInfo) {
        PropertyInfo propertyInfo1 = new PropertyInfo();
        //检验数据
        validatePropertyInfo(propertyInfo);
        //获取楼盘区域，注册区域码数组
        String[] areaCode = propertyInfo.getAreaCode();
        String[] propertyArea = propertyInfo.getPropertyArea();
        ObjectMapper objectMapper = new ObjectMapper();

        try {
            // 将数组转换为JSON格式
            String jsonAreaCode = objectMapper.writeValueAsString(areaCode);
            String jsonPropertyArea = objectMapper.writeValueAsString(propertyArea);
            // 输出结果
            System.out.println("Area Code JSON: " + jsonAreaCode);
            System.out.println("Property Area JSON: " + jsonPropertyArea);

            BeanUtils.copyProperties(propertyInfo,propertyInfo1);
            //将转化后的的数据放在propertyInfo1中
            propertyInfo1.setPropertyArea(jsonPropertyArea);
            System.out.println(432);
            propertyInfo1.setAreaCode(jsonAreaCode);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        //修改信息
        int i = propertyInfoMapper.updatePropertyInfo(propertyInfo1);
        if(i<=0){
            logger.error("信息修改失败");
            throw new BaseException("信息修改失败");
        }
        //修改状态
        updateStatus(propertyInfo.getCategoryId(),propertyInfo.getStatus());
    }

    public void validatePropertyInfo(PropertyInfoDTO propertyInfo) {
        if (propertyInfo == null) {
            throw new BaseException("修改内容不能为空");
        }

        if (!StringUtils.hasText(propertyInfo.getPropertyName())) {
            throw new BaseException("楼盘名称不能为空");
        }

        if (!StringUtils.hasText(propertyInfo.getPropertyCode())) {
            throw new BaseException("楼盘编号不能为空");
        }

        if (!StringUtils.hasText(propertyInfo.getDetailedAddress())) {
            throw new BaseException("详细地址不能为空");
        }

        if (propertyInfo.getLandArea() == null || propertyInfo.getLandArea().compareTo(BigDecimal.ZERO) <= 0) {
            throw new BaseException("占地面积不能为空且必须大于0");
        }

        if (propertyInfo.getTotalBuildingArea() == null || propertyInfo.getTotalBuildingArea().compareTo(BigDecimal.ZERO) <= 0) {
            throw new BaseException("总建筑面积不能为空且必须大于0");
        }

        if (propertyInfo.getPlotRatio() == null || propertyInfo.getPlotRatio().compareTo(BigDecimal.ZERO) <= 0) {
            throw new BaseException("容积率不能为空且必须大于0");
        }

        if (propertyInfo.getNumberOfHouseholds() == null || propertyInfo.getNumberOfHouseholds() <= 0) {
            throw new BaseException("户数不能为空且必须大于0");
        }

        if (propertyInfo.getParkingSpaces() == null || propertyInfo.getParkingSpaces() <= 0) {
            throw new BaseException("车位数不能为空且必须大于0");
        }

        if (propertyInfo.getPropertyArea() == null || propertyInfo.getPropertyArea().length == 0) {
            throw new BaseException("楼盘区域不能为空");
        }

        if (propertyInfo.getAreaCode() == null || propertyInfo.getAreaCode().length == 0) {
            throw new BaseException("注册区域码不能为空");
        }
    }

    @Override
    public PropertyInfoFeeVO getPropertyInfoFee(Long id) {
        if(id==null){
            logger.error("请选择你要查询的楼盘");
            throw new BaseException("请选择你要查询的楼盘");
        }
        PropertyInfoFeeVO propertyInfoFeeVO=projectManagementMapper.getPropertyInfoFee(id);
        if(propertyInfoFeeVO==null){
            logger.error("没有查到该楼盘的计费信息");
            throw new BaseException("没有查到该楼盘的计费信息");
        }
        return propertyInfoFeeVO;
    }

    @Override
    public List<Expenditure> getexpenditureList() {
       List<Expenditure> expenditures=projectManagementMapper.getexpenditureList();
       if(expenditures==null){
           logger.error("没有查到费项信息");
           throw new BaseException("没有查到费项信息");
       }
        return expenditures;
    }

    @Override
    public FormulaPriceVO getFormulaPriceList(Long expenditureId) {
        // 检查传入的 expenditureId 是否为 null，如果是，则记录错误日志并抛出异常
        if (expenditureId == null) {
            logger.error("请选择费项");
            throw new BaseException("请选择费项");
        }

        // 创建 FormulaPriceVO 对象，用于存储查询结果
        FormulaPriceVO formulaPriceVO = new FormulaPriceVO();

        // 查询费项对应的公式
        List<FeeFormula> formulas = queryFeeFormulas(expenditureId, 1, "公式");
        // 查询费项对应的价格
        List<FeeFormula> prices = queryFeeFormulas(expenditureId, 2, "价格");

        // 将查询结果设置到 FormulaPriceVO 对象中
        formulaPriceVO.setFormulas(formulas);
        formulaPriceVO.setPrice(prices);

        // 返回包含公式和价格信息的 FormulaPriceVO 对象
        return formulaPriceVO;
    }


    /**
     * 根据 expenditureId 和类型查询 FeeFormula 信息
     *
     * @param expenditureId 费项 ID
     * @param type 类型（1 表示公式，2 表示价格）
     * @param entityType 实体类型名称（用于日志记录）
     * @return 查询到的 FeeFormula 列表
     */
    private List<FeeFormula> queryFeeFormulas(Long expenditureId, Integer type, String entityType) {
        // 创建 LambdaQueryWrapper 对象，用于构建查询条件
        LambdaQueryWrapper<FeeFormula> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        if(type==1){
            lambdaQueryWrapper.eq(FeeFormula::getType, type)
                    .eq(FeeFormula::getExpenditureId, expenditureId)
                    .select(FeeFormula::getId, FeeFormula::getFormulaName);
        }else {
            lambdaQueryWrapper.eq(FeeFormula::getType, type)
                    .eq(FeeFormula::getExpenditureId, expenditureId)
                    .select(FeeFormula::getId, FeeFormula::getPrice);
        }

        // 执行查询并获取结果
        List<FeeFormula> results = iFeeFormulaService.list(lambdaQueryWrapper);
        // 如果查询结果为空，记录警告日志
        if (results.isEmpty()) {
            logger.warn("未找到 {} 对应的 {} 信息", expenditureId, entityType);
        }
        // 返回查询结果
        return results;
    }


    @Override
    public void add(AddFeeDTO addFeeDTO) throws JsonProcessingException {
        // 检查传入的 DTO 对象是否为 null
        validateNotNull(addFeeDTO, "请填写添加内容");
        // 验证 DTO 对象中的关键属性是否为 null 或不符合要求
        validateAddFeeDTOFields(addFeeDTO);

        // 创建 BillingAssociation 对象并复制属性
        BillingAssociation billingAssociation = new BillingAssociation();
        BeanUtils.copyProperties(addFeeDTO,billingAssociation);
        ObjectMapper objectMapper = new ObjectMapper();
        String price = objectMapper.writeValueAsString(addFeeDTO.getPrice());
        billingAssociation.setPrice(price);
        System.out.println(billingAssociation.toString());
        //判断该楼盘，费项、公式是否已经添加
        LambdaQueryWrapper<BillingAssociation> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(BillingAssociation::getExpenditureId,billingAssociation.getExpenditureId())
                .eq(BillingAssociation::getPropertyInfoId,billingAssociation.getPropertyInfoId())
                .eq(BillingAssociation::getFormulaName,billingAssociation.getFormulaName());
        if(iBillingAssociationService.getOne(lambdaQueryWrapper)!=null){
            logger.error("该费项已存在");
            throw new BaseException("该费项已存在");
        }
        // 执行添加操作
        try {
            iBillingAssociationService.save(billingAssociation);
            logger.info("费项添加成功");
        } catch (Exception e) {
            // 记录异常日志，并重新抛出异常
            logger.error("费项添加失败", e);
            throw new BaseException("费项添加失败");
        }
    }

    @Override
    public void delete(Integer id) {
        if(id==null){
            logger.error("请选择您要移除的费项");
            throw new BaseException("请选择您要移除的费项");
        }
        boolean b = iBillingAssociationService.removeById(id);
        if(b==false){
            logger.error("费项移除失败");
            throw new BaseException("费项移除失败");
        }
    }


    /**
     * 验证对象是否为 null
     *
     * @param object 待验证的对象
     * @param message 错误信息
     */
    private void validateNotNull(Object object, String message) {
        if (object == null) {
            logger.error(message);
            throw new BaseException(message);
        }
    }

    /**
     * 验证 AddFeeDTO 对象中的关键属性是否为 null 或不符合要求
     *
     * @param addFeeDTO AddFeeDTO 对象
     */
    private void validateAddFeeDTOFields(AddFeeDTO addFeeDTO) {
        // 检查关键属性是否为 null 或不符合要求
        if (addFeeDTO.getPropertyInfoId() == null) {
            logger.error("楼盘信息 ID 不能为空");
            throw new BaseException("楼盘信息 ID 不能为空");
        }

        if (addFeeDTO.getExpenditureId() == null) {
            logger.error("费项 ID 不能为空");
            throw new BaseException("费项 ID 不能为空");
        }

        if (addFeeDTO.getFormulaName() == null || addFeeDTO.getFormulaName().trim().isEmpty()) {
            logger.error("计费公式不能为空");
            throw new BaseException("计费公式不能为空");
        }

        if (addFeeDTO.getPrice() == null) {
            logger.error("价格不能为空");
            throw new BaseException("价格不能为空");
        }
    }
}
